package main

import "fmt"

func main() {

	// 切片是一个拥有相同类型元素的可变长度序列，基于数组做的一层封装，支持自动扩容
	// 每个切片都会指向一个底层数组
	// 切片是一个引用类型，内部结构包括地址、长度和容量
	// var name []T
	// var slice1 = []int{1, 3, 4}
	// fmt.Printf("值:%v,类型:%T,长度:%v,容量:%v\n", slice1, slice1, len(slice1), cap(slice1))
	// var slice2 = []int{1: 1, 3: 3, 4: 4}
	// fmt.Printf("值:%v,类型:%T,长度:%v,容量:%v\n", slice2, slice2, len(slice2), cap(slice2))
	// fmt.Println(slice2 == nil)
	// var slice3 []int
	// fmt.Printf("值:%v,类型:%T,长度:%v,容量:%v\n", slice3, slice3, len(slice3), cap(slice3))
	// fmt.Println(slice3 == nil) // 切片的默认初始值为nil

	// 循环遍历方式和数组是同样的
	// for i := 0; i < len(slice1); i++ {
	// 	fmt.Print(slice1[i])
	// }
	// fmt.Println()
	// for _, i := range slice1 {
	// 	fmt.Print(i)
	// }

	// 基于数组定义切片
	// arr1 := [5]int{1, 2, 3, 4, 5}
	// b := arr1[:]
	// c := arr1[2:4]			// 同python，左包右不包
	// fmt.Printf("%v %T %v\n", arr1, arr1, len(arr1))
	// fmt.Printf("%v %T %v\n", b, b, len(b))
	// fmt.Printf("%v %T %v\n", c, c, len(c))

	// 基于切片定义切片
	// arr1 := []int{1, 2, 3}
	// b := arr1[:]
	// c := arr1[2:3]
	// fmt.Printf("%v %T %v\n", arr1, arr1, len(arr1))
	// fmt.Printf("%v %T %v\n", b, b, len(b))
	// fmt.Printf("%v %T %v\n", c, c, len(c))

	// 切片的长度就是他所包含的元素个数，可用len()求得
	// 切片的容量是从它的第一个元素开始数，到其底层数组元素末尾的个数，可使用cap()求得
	// s := []int{1, 2, 3, 4, 5, 6}
	// fmt.Printf("长度%d 容量%d\n", len(s), cap(s))

	// a := [6]int{1, 2, 3, 4, 5, 6}
	// sa := a[1:5]
	// fmt.Printf("内容%v 长度%d 容量%d\n", sa, len(sa), cap(sa))
	// sb := sa[:3]
	// fmt.Printf("内容%v 长度%d 容量%d\n", sb, len(sb), cap(sb))
	// sc := sa[1:3]
	// fmt.Printf("内容%v 长度%d 容量%d\n", sc, len(sc), cap(sc))

	// // // 改变切片的某个元素，底层数组对应的元素值也会改变
	// sa[0] = 99
	// fmt.Printf("a:%v, sa:%v, sb:%v, sc:%v\n", a, sa, sb, sc)
	// sb[0] = 88
	// fmt.Printf("a:%v, sa:%v, sb:%v, sc:%v\n", a, sa, sb, sc)

	// // 改变底层数组的某个元素，切片对应的元素值也会改变
	// a[1] = 77
	// fmt.Printf("a:%v, sa:%v, sb:%v, sc:%v\n", a, sa, sb, sc)

	// 使用make创建切片 make([]T, size, cap), 类型、长度、容量

	// var sliceA = make([]int, 4, 8)
	// fmt.Printf("%d--%d\n", len(sliceA), cap(sliceA))

	// // 通过下标修改切片的值
	// sliceA[0] = 10
	// sliceA[1] = 11
	// fmt.Println(sliceA)

	// // 使用append给切片进行扩容
	// var sliceA []int
	// fmt.Printf("内容:%v, 长度:%v, 容量:%v\n", sliceA, len(sliceA), cap(sliceA))
	// sliceA = append(sliceA, 12)
	// fmt.Printf("内容:%v, 长度:%v, 容量:%v\n", sliceA, len(sliceA), cap(sliceA))
	// sliceA = append(sliceA, 23, 35, 465)
	// fmt.Printf("内容:%v, 长度:%v, 容量:%v\n", sliceA, len(sliceA), cap(sliceA))

	// 使用append进行切片合并
	// sliceA := []string{"python", "java"}
	// sliceB := []string{"golang"}

	// sliceA = append(sliceA, sliceB...)
	// fmt.Println(sliceA)

	// 切片的扩容策略
	// 1. 如果新申请容量大于2倍的旧容量，最终容量就是新申请的容量
	// 2. 否则如果旧切片的长度小于1024， 则最终容量就是旧容量的两倍
	// 3. 否则如果旧切片的长度大于等于1024，则最终容量从旧容量开始循环增加原来的1/4，直到最终容量大于等于新申请的容量
	// 4. 如果最终容量计算值溢出，则最终容量就是新申请容量
	// newcap = oldcap for {newcap += newcap/4}

	// var sliceA []int
	// for i := 0; i<10; i++ {
	// 	sliceA = append(sliceA, i)
	// 	fmt.Printf("%v 长度:%d 容量:%d\n", sliceA, len(sliceA), cap(sliceA))
	// }

	// // 切片Slice Copy复制切片
	// // 切片是引用类型
	// sliceA := []int{1, 2, 3, 45}
	// sliceB := sliceA
	// sliceB[0] = 11
	// fmt.Println(sliceA)
	// fmt.Println(sliceB)

	// // 使用copy复制切片，前后两者互不影响（深拷贝）
	sliceA := []int{1, 2, 3, 45}
	sliceB := make([]int, 4, 5)
	copy(sliceB, sliceA)
	sliceB[0] = 11
	fmt.Println(sliceA)
	fmt.Println(sliceA[3:1])
	fmt.Println(sliceB)

	// // Golang中并没有删除切片元素的专用方法，我们可以使用切片本身的特性来删除元素
	// // 删除35， 36
	// sliceA := []int{30, 31, 32, 33, 34, 35, 36, 37}
	// sliceA = append(sliceA[:5], sliceA[7:]...)
	// fmt.Println(sliceA)

	// 切片的选择排序 O(n^2)
	// var slice1 = []int{9, 10, 15, 7, 3, 5, 4}
	// for i := 0; i < len(slice1); i++ {
	// 	for j := i + 1; j < len(slice1); j++ {
	// 		if slice1[j] < slice1[i] {
	// 			slice1[i], slice1[j] = slice1[j], slice1[i]
	// 		}
	// 	}
	// }
	// fmt.Println(slice1)

	// // 切片的冒泡排序 O(n^2)
	// var slice2 = []int{9, 10, 15, 7, 3, 5, 4}
	// for i := len(slice2)-1; i >=0; i-- {
	// 	for j := 0; j < i ; j++ {
	// 		if slice2[j] > slice2[j+1] {
	// 			slice2[j], slice2[j+1] = slice2[j+1], slice2[j]
	// 		}
	// 	}
	// }
	// fmt.Println(slice2)

	// sort包排序
	// sort.Ints()、 sort.Float64s()、 sort.Strings()

	// // 升序
	// intList := []int{2, 4, 3, 5, 7, 6, 9, 8, 1, 0}
	// sort.Ints(intList)
	// fmt.Println(intList)

	// // 降序
	// intList := []int{2, 4, 3, 5, 7, 6, 9, 8, 1, 0}
	// sort.Sort(sort.Reverse(sort.IntSlice(intList)))
	// fmt.Println(intList)
}
